#ifndef __MY_SERVER__
#define __MY_SERVER__
#include "data.hpp"
#include "config.hpp"
#include "httplib.h"

extern cloud::DataManager *_data;
namespace cloud
{
    class Service
    {
    private:
        int _sever_port;
        std::string _server_ip;
        std::string _download_prefix;
        httplib::Server _server;

    private:
        static void Upload(const httplib::Request &req, httplib::Response &rsp) // 文件上传请求函数
        {
            // 获取请求
            auto ret = req.has_file("file"); // 判断是否有文件上传
            if (ret == false)
            {
                rsp.status = 400;
                return;
            }
            const auto &file = req.get_file_value("file"); // 有文件上传，获取文件数据
            // 需要将文件数据拷贝到指定目录下./backdir/
            Config *config = Config::GetInstance();
            std::string real_path = config->GetBackDir() + FileUtil(file.filename).FileName();
            FileUtil fu(real_path);
            fu.SetContent(file.content);
            // 备份文件信息
            BackupInfo info;
            info.NewBackupInfo(real_path);
            _data->Insert(info);
        }
        static std::string TotiemStr(const time_t &time)
        {
            return std::ctime(&time);
        }
        static void ListShow(const httplib::Request &req, httplib::Response &rsp) // 文件列表请求函数
        {
            // 1.获取备份信息
            std::vector<BackupInfo> arry;
            _data->GetAll(&arry);
            // 2.将备份信息转换为页面,根据备份信息组织html数据
            std::stringstream ss;
            std::string html = "<html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\"><title>Download Center</title><style>body{font-family:Arial,sans-serif;margin:20px;background-color:#f4f4f4;color:#333;}h1{color:#5a5a5a;text-align:center;}table{width:100%;border-collapse:collapse;margin-top:20px;}th,td{border:1px solid #ddd;padding:8px;text-align:left;}th{background-color:#f2f2f2;text-align:center;}td:nth-child(1){text-align:center;}td:nth-child(2){text-align:center;}td:nth-child(3){text-align:center;}a{text-decoration:none;color:#007bff;}a:hover{text-decoration:underline;}</style></head>";
            // ss << "<html><head><title>Download</title></head>";
            // ss << "<body><h1>Download</h1><table>";
            ss << html;
            std::string html1 = "<body><h1>DownloadCenter</h1><table><thead><tr><th>FileName</th><th>Modified</th><th>Size</th></tr></thead><tbody>";
            ss << html1;
            for (auto &a : arry)
            {
                ss << "<tr>";
                std::string filename = FileUtil(a.real_path).FileName();
                ss << "<td><a href=\"" << a.url_path << "\">" << filename << "</a></td>";
                ss << "<td align=\"right\">" << TotiemStr(a.atime) << "</td>";
                size_t size = a.fsize / 1024 == 0 ? 1 : a.fsize / 1024;
                ss << "<td align=\"right\">" << size << "K" << "</td>";
                ss << "</tr>";
            }
            ss << "</tbody></table></body></html>";
            // 3.返回结果
            rsp.body = ss.str();
            rsp.set_header("Content-Type", "text/html");
            rsp.status = 200;
        }
        static std::string GetETag(BackupInfo &info)
        {
            std::string etags;
            FileUtil fu(info.real_path);
            etags += fu.FileName();
            etags += '-';
            etags += std::to_string(info.fsize);
            etags += '-';
            etags += std::to_string(info.mtime);
            return etags;
        }
        static void Download(const httplib::Request &req, httplib::Response &rsp) // 文件下载请求函数
        {
            // 1.获取客户端请求的资源路径path
            std::string url_path = req.path;
            // 2.根据资源路径，获取文件备份信息
            BackupInfo info;
            _data->GetOneByUrl(url_path, &info);
            // 3.判断文件是否被压缩，如果被压缩，需要先解压
            if (info.pack_flag == true)
            {
                FileUtil fu(info.pack_path);
                fu.UnCompress(info.real_path);
                // 4.删除压缩包，修改备份信息(已经没有被压缩)
                fu.Remove();
                info.pack_flag = false;
                _data->Updata(info);
            }
            // 5.读取文件数据，放入rsp.body中
            FileUtil fu(info.real_path);
            // 设置断点续传
            bool retrans = false;
            std::string old_etag;
            if (req.has_header("If-Range")) // 判断头部是否设置了"If-Range"字段请求，没有设置"If-Range"字段就正常下载即文件下载
            {
                old_etag = req.get_header_value("If-Range");
                // 如果设置"If-Range"字段且文件的数据被修改了，就进行正常下载即文件下载，否则进行断点续传
                if (old_etag == GetETag(info))
                    retrans = true;
            }
            if (retrans == false)
            {
                fu.GetContent(&rsp.body);
                // 6.设置响应头部字段：ETags: "filename-size-mtime一个能够唯一标识文件的数据",Accept-Ranges:bytes
                rsp.set_header("ETag", GetETag(info));
                rsp.set_header("Accept-Ranges", "bytes");
                rsp.set_header("Content-Type", "application/octet-stream");
                rsp.status = 200;
            }
            else
            {
                // 因为httplib库里面已经实现了断点续传的功能，所以我们不需要进行过多的操作，只需要我们用户将数据读取到
                // rsp.body中，它内部会根据请求区间，将指定的区间数据进行响应
                // std::string range = req.get_header_val("Range");bytes = start-end;
                fu.GetContent(&rsp.body);
                // 6.设置响应头部字段：ETags: "filename-size-mtime一个能够唯一标识文件的数据",Accept-Ranges:bytes
                rsp.set_header("ETag", GetETag(info));
                rsp.set_header("Accept-Ranges", "bytes");
                //rsp.set_header("Content-Range","bytes start-end/fsize");
                rsp.set_header("Content-Type", "application/octet-stream");
                rsp.status = 206; // 支持断点续传的状态码->区间请求响应的是206
            }
        }

    public:
        Service()
        {
            Config *config = Config::GetInstance();
            _sever_port = config->GetServerPort();
            _server_ip = config->GetServerIp();
            _download_prefix = config->GetDownloadPrefix();
        }
        bool RunModule()
        {
            _server.Post("/upload", Upload);
            _server.Get("/listshow", ListShow);
            _server.Get("/", ListShow);
            std::string download_url = _download_prefix + "(.*)"; // 文件下载的路径名称
            _server.Get(download_url, Download);
            _server.listen(_server_ip, _sever_port); // 问题2：怎么服务器运行一次就断了？？ _server_ip需要使用本地的IP地址，阿里云centos7 Linux可以用ifconfig查询
            return true;
        }
    };

}

#endif